package com.xingchen.feima.star.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xingchen.feima.common.utils.R;
import com.xingchen.feima.star.entity.Component;
import com.xingchen.feima.star.entity.MinimumCoolingTime;
import com.xingchen.feima.star.entity.Range;
import com.xingchen.feima.star.entity.Unit;
import com.xingchen.feima.star.service.ComponentService;
import com.xingchen.feima.star.service.MinimumCoolingTimeService;
import com.xingchen.feima.star.service.RangeService;
import com.xingchen.feima.star.service.UnitService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 组件 前端控制器
 * </p>
 *
 * @author yangxc
 * @since 2025-02-11
 */
@Api(tags = "组件管理")
@RestController
@RequestMapping("/star/component")
public class ComponentController {

    @Autowired
    private ComponentService componentService;

    @Autowired
    private RangeService rangeService;

    @Autowired
    private MinimumCoolingTimeService minimumCoolingTimeService;

    @Autowired
    private UnitService unitService;


    // 根据可外运起始日期计算各机组的可外运量
    @ApiOperation(value = "根据可外运起始日期计算各机组的可外运量")
    @PostMapping("/getUnitListWithQuantityTransferredOut")
    public R getUnitListWithQuantityTransferredOut(
            @ApiParam(name = "startDate", value = "可外运起始日期", required = true)
            @RequestBody String startDate) {
        List<Unit> unitList = unitService.list(null);
        for (Unit unit : unitList) {
            int count = componentService.count(new LambdaQueryWrapper<Component>().eq(Component::getUnitId, unit.getId()).le(Component::getTheEarliestDateOfOutwardTransport, startDate));
            unit.setQuantityTransferredOut((long) count);
        }

        return R.ok().data("items", unitList);
    }

    @ApiOperation(value = "根据机组id获取组件列表")
    @GetMapping("/getComponentListByUnitId/{id}")
    public R getComponentListByUnitId(
            @ApiParam(name = "id", value = "机组id", required = true)
            @PathVariable Long id){
        List<Component> list = componentService.list(new QueryWrapper<Component>().eq("unit_id", id));
        return R.ok().data("items", list);
    }

    @ApiOperation(value = "新增组件")
    @PostMapping("")
    public R add(
            @ApiParam(name = "component", value = "组件对象", required = true)
            @RequestBody Component component){

        // 根据燃耗和初始富集度确定组件是低燃耗组件还是高燃耗组件
        // 然后在低燃耗组件表或者高燃耗组件表中得到该组件的最小冷却时间/年，转换成天数（按照一年365天计算），并计算可外运的最早日期

        // 获取低燃耗组件的燃耗范围列表和初始铀富集度范围列表
        List<Range> lowBurnupBurnupRangeList = rangeService.list(new LambdaQueryWrapper<Range>().eq(Range::getIsLowBurnupOrHighBurnup, 0).eq(Range::getIsBurnupOrInitialUraniumEnrichment, 0));
        List<Range> lowBurnupInitialUraniumEnrichmentRangeList = rangeService.list(new LambdaQueryWrapper<Range>().eq(Range::getIsLowBurnupOrHighBurnup, 0).eq(Range::getIsBurnupOrInitialUraniumEnrichment, 1));
        // 获取高燃耗组件的燃耗范围列表和初始铀富集度范围列表
        List<Range> highBurnupBurnupRangeList = rangeService.list(new LambdaQueryWrapper<Range>().eq(Range::getIsLowBurnupOrHighBurnup, 1).eq(Range::getIsBurnupOrInitialUraniumEnrichment, 0));
        List<Range> highBurnupInitialUraniumEnrichmentRangeList = rangeService.list(new LambdaQueryWrapper<Range>().eq(Range::getIsLowBurnupOrHighBurnup, 1).eq(Range::getIsBurnupOrInitialUraniumEnrichment, 1));

        // 获取低燃耗组件最小冷却时间列表、获取高燃耗组件最小冷却时间列表
        List<MinimumCoolingTime> lowBurnupMinimumCoolingTimeList = minimumCoolingTimeService.list(new LambdaQueryWrapper<MinimumCoolingTime>().eq(MinimumCoolingTime::getIsLowBurnupOrHighBurnup, 0));
        List<MinimumCoolingTime> highBurnupMinimumCoolingTimeList = minimumCoolingTimeService.list(new LambdaQueryWrapper<MinimumCoolingTime>().eq(MinimumCoolingTime::getIsLowBurnupOrHighBurnup, 1));

        // 给低燃耗组件最小冷却时间列表中的每个元素的燃耗范围和初始富集度范围属性赋值
        for (MinimumCoolingTime lowBurnupMinimumCoolingTime : lowBurnupMinimumCoolingTimeList) {
            for (Range lowBurnupBurnupRange : lowBurnupBurnupRangeList) {
                if (lowBurnupMinimumCoolingTime.getBurnupRangeId().equals(lowBurnupBurnupRange.getId())) {
                    lowBurnupMinimumCoolingTime.setBurnupRange(lowBurnupBurnupRange);
                    break;
                }
            }
            for (Range lowBurnupInitialUraniumEnrichmentRange : lowBurnupInitialUraniumEnrichmentRangeList) {
                if (lowBurnupMinimumCoolingTime.getInitialUraniumEnrichmentRangeId().equals(lowBurnupInitialUraniumEnrichmentRange.getId())) {
                    lowBurnupMinimumCoolingTime.setInitialUraniumEnrichmentRange(lowBurnupInitialUraniumEnrichmentRange);
                    break;
                }
           }
        }

        // 给高燃耗组件最小冷却时间列表中的每个元素的燃耗范围和初始富集度范围属性赋值
        for (MinimumCoolingTime highBurnupMinimumCoolingTime : highBurnupMinimumCoolingTimeList) {
            for (Range highBurnupBurnupRange : highBurnupBurnupRangeList) {
                if (highBurnupMinimumCoolingTime.getBurnupRangeId().equals(highBurnupBurnupRange.getId())) {
                    highBurnupMinimumCoolingTime.setBurnupRange(highBurnupBurnupRange);
                    break;
                }
            }
            for (Range highBurnupInitialUraniumEnrichmentRange : highBurnupInitialUraniumEnrichmentRangeList) {
                if (highBurnupMinimumCoolingTime.getInitialUraniumEnrichmentRangeId().equals(highBurnupInitialUraniumEnrichmentRange.getId())) {
                    highBurnupMinimumCoolingTime.setInitialUraniumEnrichmentRange(highBurnupInitialUraniumEnrichmentRange);
                    break;
                }
           }
        }

        Map<String, Object> lowOrHighAndMinimumCoolingTimeValue = getLowOrHighAndMinimumCoolingTimeValue(lowBurnupMinimumCoolingTimeList, component);
        // 只要有一个为null，则在该表中无法得到最小冷却时间，去高燃耗组件表中查找；若最小冷却时间为-1，则也无法得到最小冷却时间
        if (lowOrHighAndMinimumCoolingTimeValue.get("lowOrHigh") == null || lowOrHighAndMinimumCoolingTimeValue.get("minimumCoolingTimeValue") == null) {
            Map<String, Object> lowOrHighAndMinimumCoolingTimeValueInner = getLowOrHighAndMinimumCoolingTimeValue(highBurnupMinimumCoolingTimeList, component);
            if (lowOrHighAndMinimumCoolingTimeValueInner.get("lowOrHigh") == null || lowOrHighAndMinimumCoolingTimeValueInner.get("minimumCoolingTimeValue") == null) {
                return R.error().message("该组件在低燃耗组件表中和高燃耗组件表中均无法得到最小冷却时间");
            } else {
                if ((Double)lowOrHighAndMinimumCoolingTimeValueInner.get("minimumCoolingTimeValue") < 0) {
                    return R.error().message("该组件在高燃耗组件表中的最小冷却时间为-1");
                }
                component.setLowOrHigh((Integer) lowOrHighAndMinimumCoolingTimeValueInner.get("lowOrHigh"));
                component.setYearsOfPlacement((Double) lowOrHighAndMinimumCoolingTimeValueInner.get("minimumCoolingTimeValue"));
            }
        } else {
            if ((Double)lowOrHighAndMinimumCoolingTimeValue.get("minimumCoolingTimeValue") < 0) {
                return R.error().message("该组件在低燃耗组件表中的最小冷却时间为-1");
            }
            component.setLowOrHigh((Integer) lowOrHighAndMinimumCoolingTimeValue.get("lowOrHigh"));
            component.setYearsOfPlacement((Double) lowOrHighAndMinimumCoolingTimeValue.get("minimumCoolingTimeValue"));
        }

        // 将放置的年数乘以365，向上取整
        component.setDaysOfPlacement((int) Math.ceil(component.getYearsOfPlacement() * 365));
        // 将入池的日期加上放置的天数得到可外运的最早日期
        component.setTheEarliestDateOfOutwardTransport(component.getTimeToEnterThePool().plusDays(component.getDaysOfPlacement()));


        componentService.save(component);
        return R.ok().message("添加成功");
    }

    public Map<String, Object> getLowOrHighAndMinimumCoolingTimeValue(List<MinimumCoolingTime> minimumCoolingTimeList, Component component) {

        Map<String, Object> map = new HashMap<>();
        Integer mapLowOrHigh = null;
        Double mapMinimumCoolingTimeValue = null;

        // 计算是低燃耗还是高燃耗、并得到最小冷却时间/年
        for (MinimumCoolingTime minimumCoolingTime : minimumCoolingTimeList) {
            Integer lowOrHigh = null;
            Double minimumCoolingTimeValue = null;

            Range burnupRange = minimumCoolingTime.getBurnupRange();
            Range initialUraniumEnrichmentRange = minimumCoolingTime.getInitialUraniumEnrichmentRange();
            // 判断组件燃耗是否在当前最小冷却时间的燃耗范围内
            if (burnupRange.getIsGetLowValue() == 0 && burnupRange.getIsGetHighValue() == 0) {
                if (component.getBurnup() > burnupRange.getLowValue() && component.getBurnup() < burnupRange.getHighValue()) {
                    lowOrHigh = burnupRange.getIsLowBurnupOrHighBurnup();
                }
            }
            else if (burnupRange.getIsGetLowValue() == 1 && burnupRange.getIsGetHighValue() == 1) {
                if (component.getBurnup() >= burnupRange.getLowValue() && component.getBurnup() <= burnupRange.getHighValue()) {
                    lowOrHigh = burnupRange.getIsLowBurnupOrHighBurnup();
                }
            }
            else if (burnupRange.getIsGetLowValue() == 1 && burnupRange.getIsGetHighValue() == 0) {
                if (component.getBurnup() >= burnupRange.getLowValue() && component.getBurnup() < burnupRange.getHighValue()) {
                    lowOrHigh = burnupRange.getIsLowBurnupOrHighBurnup();
                }
            }
            else if (burnupRange.getIsGetLowValue() == 0 && burnupRange.getIsGetHighValue() == 1) {
                if (component.getBurnup() > burnupRange.getLowValue() && component.getBurnup() <= burnupRange.getHighValue()) {
                    lowOrHigh = burnupRange.getIsLowBurnupOrHighBurnup();
                }
            }

            // 如果组件燃耗不在该范围内，直接下一个循环
            if (lowOrHigh == null) {
                continue;
            }
            // 如果组件燃耗在该范围内，判断组件初始富集度是否在当前最小冷却时间的初始富集度范围内，并得到最小冷却时间
            if (initialUraniumEnrichmentRange.getIsGetLowValue() == 0 && initialUraniumEnrichmentRange.getIsGetHighValue() == 0) {
                if (component.getInitialUraniumEnrichment() > initialUraniumEnrichmentRange.getLowValue() && component.getInitialUraniumEnrichment() < initialUraniumEnrichmentRange.getHighValue()) {
                    minimumCoolingTimeValue = minimumCoolingTime.getMinimumCoolingTimeValue();
                }
            }
            else if (initialUraniumEnrichmentRange.getIsGetLowValue() == 1 && initialUraniumEnrichmentRange.getIsGetHighValue() == 1) {
                if (component.getInitialUraniumEnrichment() >= initialUraniumEnrichmentRange.getLowValue() && component.getInitialUraniumEnrichment() <= initialUraniumEnrichmentRange.getHighValue()) {
                    minimumCoolingTimeValue = minimumCoolingTime.getMinimumCoolingTimeValue();
                }
            }
            else if (initialUraniumEnrichmentRange.getIsGetLowValue() == 1 && initialUraniumEnrichmentRange.getIsGetHighValue() == 0) {
                if (component.getInitialUraniumEnrichment() >= initialUraniumEnrichmentRange.getLowValue() && component.getInitialUraniumEnrichment() < initialUraniumEnrichmentRange.getHighValue()) {
                    minimumCoolingTimeValue = minimumCoolingTime.getMinimumCoolingTimeValue();
                }
            }
            else if (initialUraniumEnrichmentRange.getIsGetLowValue() == 0 && initialUraniumEnrichmentRange.getIsGetHighValue() == 1) {
                if (component.getInitialUraniumEnrichment() > initialUraniumEnrichmentRange.getLowValue() && component.getInitialUraniumEnrichment() <= initialUraniumEnrichmentRange.getHighValue()) {
                    minimumCoolingTimeValue = minimumCoolingTime.getMinimumCoolingTimeValue();
                }
            }

            // 如果组件初始富集度不在该范围内，直接下一个循环
            if (minimumCoolingTimeValue == null) {
                continue;
            }

            // 组件的燃耗和初始富集度都在该最小冷却时间的燃耗和初始富集度范围内
            mapLowOrHigh = lowOrHigh;
            mapMinimumCoolingTimeValue = minimumCoolingTimeValue;
            break;

        }

        map.put("lowOrHigh", mapLowOrHigh);
        map.put("minimumCoolingTimeValue", mapMinimumCoolingTimeValue);

        return map;
    }


    @ApiOperation(value = "根据id查询组件")
    @GetMapping("/{id}")
    public R getById(
            @ApiParam(name = "id", value = "组件id", required = true)
            @PathVariable Long id){

        Component component = componentService.getById(id);
        return R.ok().data("items", component);
    }

    @ApiOperation(value = "根据id修改组件")
    @PutMapping("")
    public R updateById(
            @ApiParam(name = "component", value = "组件对象", required = true)
            @RequestBody Component component){

        // 根据燃耗和初始富集度确定组件是低燃耗组件还是高燃耗组件
        // 然后在低燃耗组件表或者高燃耗组件表中得到该组件的最小冷却时间/年，转换成天数（按照一年365天计算），并计算可外运的最早日期

        // 获取低燃耗组件的燃耗范围列表和初始铀富集度范围列表
        List<Range> lowBurnupBurnupRangeList = rangeService.list(new LambdaQueryWrapper<Range>().eq(Range::getIsLowBurnupOrHighBurnup, 0).eq(Range::getIsBurnupOrInitialUraniumEnrichment, 0));
        List<Range> lowBurnupInitialUraniumEnrichmentRangeList = rangeService.list(new LambdaQueryWrapper<Range>().eq(Range::getIsLowBurnupOrHighBurnup, 0).eq(Range::getIsBurnupOrInitialUraniumEnrichment, 1));
        // 获取高燃耗组件的燃耗范围列表和初始铀富集度范围列表
        List<Range> highBurnupBurnupRangeList = rangeService.list(new LambdaQueryWrapper<Range>().eq(Range::getIsLowBurnupOrHighBurnup, 1).eq(Range::getIsBurnupOrInitialUraniumEnrichment, 0));
        List<Range> highBurnupInitialUraniumEnrichmentRangeList = rangeService.list(new LambdaQueryWrapper<Range>().eq(Range::getIsLowBurnupOrHighBurnup, 1).eq(Range::getIsBurnupOrInitialUraniumEnrichment, 1));

        // 获取低燃耗组件最小冷却时间列表、获取高燃耗组件最小冷却时间列表
        List<MinimumCoolingTime> lowBurnupMinimumCoolingTimeList = minimumCoolingTimeService.list(new LambdaQueryWrapper<MinimumCoolingTime>().eq(MinimumCoolingTime::getIsLowBurnupOrHighBurnup, 0));
        List<MinimumCoolingTime> highBurnupMinimumCoolingTimeList = minimumCoolingTimeService.list(new LambdaQueryWrapper<MinimumCoolingTime>().eq(MinimumCoolingTime::getIsLowBurnupOrHighBurnup, 1));

        // 给低燃耗组件最小冷却时间列表中的每个元素的燃耗范围和初始富集度范围属性赋值
        for (MinimumCoolingTime lowBurnupMinimumCoolingTime : lowBurnupMinimumCoolingTimeList) {
            for (Range lowBurnupBurnupRange : lowBurnupBurnupRangeList) {
                if (lowBurnupMinimumCoolingTime.getBurnupRangeId().equals(lowBurnupBurnupRange.getId())) {
                    lowBurnupMinimumCoolingTime.setBurnupRange(lowBurnupBurnupRange);
                    break;
                }
            }
            for (Range lowBurnupInitialUraniumEnrichmentRange : lowBurnupInitialUraniumEnrichmentRangeList) {
                if (lowBurnupMinimumCoolingTime.getInitialUraniumEnrichmentRangeId().equals(lowBurnupInitialUraniumEnrichmentRange.getId())) {
                    lowBurnupMinimumCoolingTime.setInitialUraniumEnrichmentRange(lowBurnupInitialUraniumEnrichmentRange);
                    break;
                }
            }
        }

        // 给高燃耗组件最小冷却时间列表中的每个元素的燃耗范围和初始富集度范围属性赋值
        for (MinimumCoolingTime highBurnupMinimumCoolingTime : highBurnupMinimumCoolingTimeList) {
            for (Range highBurnupBurnupRange : highBurnupBurnupRangeList) {
                if (highBurnupMinimumCoolingTime.getBurnupRangeId().equals(highBurnupBurnupRange.getId())) {
                    highBurnupMinimumCoolingTime.setBurnupRange(highBurnupBurnupRange);
                    break;
                }
            }
            for (Range highBurnupInitialUraniumEnrichmentRange : highBurnupInitialUraniumEnrichmentRangeList) {
                if (highBurnupMinimumCoolingTime.getInitialUraniumEnrichmentRangeId().equals(highBurnupInitialUraniumEnrichmentRange.getId())) {
                    highBurnupMinimumCoolingTime.setInitialUraniumEnrichmentRange(highBurnupInitialUraniumEnrichmentRange);
                    break;
                }
            }
        }

        Map<String, Object> lowOrHighAndMinimumCoolingTimeValue = getLowOrHighAndMinimumCoolingTimeValue(lowBurnupMinimumCoolingTimeList, component);
        // 只要有一个为null，则在该表中无法得到最小冷却时间，去高燃耗组件表中查找；若最小冷却时间为-1，则也无法得到最小冷却时间
        if (lowOrHighAndMinimumCoolingTimeValue.get("lowOrHigh") == null || lowOrHighAndMinimumCoolingTimeValue.get("minimumCoolingTimeValue") == null) {
            Map<String, Object> lowOrHighAndMinimumCoolingTimeValueInner = getLowOrHighAndMinimumCoolingTimeValue(highBurnupMinimumCoolingTimeList, component);
            if (lowOrHighAndMinimumCoolingTimeValueInner.get("lowOrHigh") == null || lowOrHighAndMinimumCoolingTimeValueInner.get("minimumCoolingTimeValue") == null) {
                return R.error().message("该组件在低燃耗组件表中和高燃耗组件表中均无法得到最小冷却时间");
            } else {
                if ((Double)lowOrHighAndMinimumCoolingTimeValueInner.get("minimumCoolingTimeValue") < 0) {
                    return R.error().message("该组件在高燃耗组件表中的最小冷却时间为-1");
                }
                component.setLowOrHigh((Integer) lowOrHighAndMinimumCoolingTimeValueInner.get("lowOrHigh"));
                component.setYearsOfPlacement((Double) lowOrHighAndMinimumCoolingTimeValueInner.get("minimumCoolingTimeValue"));
            }
        } else {
            if ((Double)lowOrHighAndMinimumCoolingTimeValue.get("minimumCoolingTimeValue") < 0) {
                return R.error().message("该组件在低燃耗组件表中的最小冷却时间为-1");
            }
            component.setLowOrHigh((Integer) lowOrHighAndMinimumCoolingTimeValue.get("lowOrHigh"));
            component.setYearsOfPlacement((Double) lowOrHighAndMinimumCoolingTimeValue.get("minimumCoolingTimeValue"));
        }

        // 将放置的年数乘以365，向上取整
        component.setDaysOfPlacement((int) Math.ceil(component.getYearsOfPlacement() * 365));
        // 将入池的日期加上放置的天数得到可外运的最早日期
        component.setTheEarliestDateOfOutwardTransport(component.getTimeToEnterThePool().plusDays(component.getDaysOfPlacement()));

        componentService.updateById(component);
        return R.ok().message("修改成功");
    }

    @ApiOperation(value = "根据id删除组件")
    @DeleteMapping("/{id}")
    public R removeById(
            @ApiParam(name = "id", value = "组件id", required = true)
            @PathVariable Long id){

        componentService.removeById(id);
        return R.ok().message("删除成功");
    }

    @ApiOperation("根据id列表批量删除组件")
    @DeleteMapping("/batchRemove")
    public R batchRemove(
            @ApiParam(name = "idList", value = "id列表", required = true)
            @RequestBody List<Long> idList) {

        componentService.removeByIds(idList);
        return R.ok().message("批量删除成功");
    }
}

